Adding it your Application
==========================

Add "VideoCapture.lib" and "VideoCapture.h" to your project
Under project Settings tick "Ignore all default libraries"
#include "VideoCapture.h" in your main source file
If you want to use the "Compression Properties" Dialog you will have
to insert the dialog template from Dialog.rc



Using it in your Application
============================

1) Create a CVideoCapture Object


2) Call its Create() method to create internally needed objects.

   When finished with the object you can call Destroy() (it will be
   called automatically anyway by the destructor).


3) Call Init() to initialize the internal objects.
   
   If you have stopped recording and wish to start a new recording
   call Init() (you can Cleanup() the objects after you have
   finished with them, or it will be automatically be taken care of
   by the destructor or Init() ).


4) Next create a VideoProperties object and pass it into the
   CVideoCapture objects CreateFilterGraphManager() method.

   For more information about VideoProperties see the section below.


5) Call AddImage() or AddBitmap() with a pointer to the image data.

   AddImage expects no header info whereas AddBitmap expects both
   the BITMAPFILEHEADER and BITMAPINFOHEADER structures.

   The second parameter indicates in milliseconds how long the image
   should appear for (negative or zero values will cause the image
   to be ignored and the function will act as if the parameters are
   {NULL,0} ).

   If the first parameter is NULL the return value will indicate
   whether it is ready for new data. If the return value is false
   try Sleep(1) (or any other time consuming task) before trying to
   add the new frame again, as it is likely to improve the
   performance.

   If the first parameter is not NULL the functions return whether
   they succeeded in adding the image. If the return value is false
   this may mean it is not ready for new data yet or there was a
   more serious error.

   The image data should have the same format as specified in the
   VideoProperties, minimal error checking is done by these
   functions. Also every row (ie fixed height coordinate) should be
   DWORD aligned (see bitmap specification).

   If the "bCreateBuffer" is set to true, in the VideoProperties
   object used in step 4 above, the functions make a copy of the data
   that is passed in, so the pointer to the data, and the data
   itself, can be used in any way the user sees fit, without having
   to worry about whether the data is being used by some other
   internal processes. If however it is set to false the user must
   ensure the data is not changed until a second call to AddImage()
   or AddBitmap() returns true (whether the first parameter is NULL
   or a pointer to another buffer containing data).


6) When you want to stop adding images call End() (optionally you
   can call Cleanup()). To start a new video call Init() and
   continue from step 3).


7) When you no longer want use of the VideoCapture object call
   Destroy() or you can let the destructor do it for you.



Errors, Return Values, and Typedefs
===================================

All functions that have a bool value return true on success and
false on failure. Functions that return VC_HRESULT can be tested for
success and failure using SUCCEEDED() and FAILED(). It is up to the
user to test for failures as the objects can automatically call
Cleanup() which can cause unexpected results. 

If a failure occurs call GetError(). If it returns true it will have
additional information which can be accessed by passing a pointer to
a char*. Note that if Cleanup() is called (directly or indirectly)
the information will be lost, and if Destroy() is called it may no
longer point to an array of chars. Always check if the pointer it
returns is NULL. (If NULL is passed into the function it will not
attempt to return a pointer to an array of chars).

You can check how many bytes AddImage() will copy by calling
GetBufferSize() AFTER you have called CreateFilterGraph() (otherwise
it will cause an error and Cleanup() will be called). This is so the
user can do some error checking. Note that the Buffer size will not
be allowed to change (until Init() has been called again) and calls
to GetBufferSize() will be costly (time wise), so it is recommended
you call it once and store the result.

Note that various types are introduced in the "VideoCapture.h" as it
does not include "windows.h". These are equivalent to their
counterparts which do not have the prefix VC_ (eg. WCHAR is exactly
the same as VC_WCHAR).



Video Properties
================

A VideoProperties object is required by CreateFilterGraphManager()
after it returns the user can do what he wishes with the object, the
library will not assume it still exists.


The VideoProperties object has the following members that you need
to set:

char* name - The name of the file that will be created. Note that it
will create any folders that do not exist, if possible (otherwise it
will fail and you will have to call Init() again). For example a 
value of "videos/MyVideo.avi" will create a folder called videos in
the same directory as the application and create a video called
MyVideo.avi. Currently only avi files are supported, and it is up to
the user to free any memory held by "name" (none will be allocated
by CreateFilterGraphManager() ) 

bool bWriteOverIfExists - If set to true it will wipe over any files
it finds that have the same name and are in the same folder. If set
to false and the file already exists then CreateFilterGraphManager()
will fail.

int width - The width of the image ie. the number of pixels in one
row. The value can not be negative or zero and should not take into
account DWORD alignment.

int height - The height of the image ie. the number of pixels in one
column. If this value is negative the image will be flipped. It can
not however be zero.

int format - Use one of the enumerated ClrTypes. Currently only
RGB_555, RGB_565, RGB_24, and RGB_32 are supported.

bool bCreateBuffer - If true the user needs not worry about whether
internal processes require the data that is passed in the first
parameter of AddImage() or AddBitmap() to remain unmodified. If false
the user must not change the data until a new call of the functions
return true. Although this means additional work for the user,
internally the data is copied one less time so in theory the entire
process should be faster.

bool bUseTheseSettings - Set it to true if you want the information
provided by the two members below to completely define the
compression. If set to false the compression properties should be set
at runtime by the "Compression Properties Dialog" with a call to
DisplayCompressorDialog(). For more information see the relevant
section below.

bool bUseCompressor - Set it to true if you want to compress the
video before writing it into the file. This is highly recommended as
even though compression might mean a poorer quality picture when
playing, uncompressed video can take up a ridiculous amount of hard
disk space. If you set this parameter to true then you will have to
set the compressProp member, otherwise you can ignore it.

CompressorPropertiesToSet compressProp - You only need to set this
if you are using a compressor (ie bUseCompressor is set to true).
For more information on CompressorPropertiesToSet see the topic
below on Compressor Properties.



Compressor Properties
=====================

Once Init() has been called (successfully) a full list of avi
compressors can be obtained using GetAllCompressorInfo() (see the id
member variable below for more information). A compressors
information can be stored in a CompressorProperties object.

The CompressorProperties object has the following members:

bool bNameFilledIn - If true it specifies that the FriendlyName
member holds a valid name. The constructor defaults this value to
false, it is usually only set by a call to GetAllCompressorInfo(). If
it is set to true by GetAllCompressorInfo() it also means the id
member is valid, otherwise the id member should just be ignored.

char FriendlyName[256] - A null terminated string that gives a
readable name for the compressor eg. "Microsoft Video 1". If
bNameFilledIn is false then the array will contain nonsense.

int id - This value is set by a successful call to
GetAllCompressorInfo(). GetAllCompressorInfo() expects the address of
a pointer to a pointer to a CompressorProperties object. The value of
the pointer to the CompressorProperties object should be initialized
to NULL and if the function is successful it will point to an array
of CompressorProperties objects. It will work out how many
compressors are registered and create the array dynamically using the
"new" operator. It is up to the user to call "delete []" on the array
that is returned via the first parameter of the function. The first
element of the array has an id value equal to the total number of
objects in the array. Infact array[j].id+j also equals the total
number of CompressorProperties objects allocated (regardless of the
value of j).

bool bInfoFilledIn - Internally FillCompressorProperties() is called
if it succeeded this value will be true. This value is defaulted to
false by the constructor. If the value is true you can use the four
members below to determine the information the function was able to
obtain.

bool bHas_IAMVideoCompression_Interface - If true it indicates that
the compressor has an IAMVideoCompression Interface (see DirectX
documentation). The properties obtained by this interface are stored
in the VideoCompressionProperties member. If false however the
VideoCompressionProperties should be ignored.

VideoCompressionProperties vcp - This structure is filled in with
information obtained by the IAMVideoCompression Interface
(particularly from the GetInfo() method exposed by the interface).
The members of this class should be obvious from the DirectX
documentation on the interface. The pszVersion and pszDescription
members are initialized to NULL by the constructor and delete [] will
automatically be called by the destructor on the two pointers. I have
never got any useful information from these pointers so am unsure
whether my implementation of getting information is correct.

bool bHas_IAMVfwCompressDialogs_Interface - If true it indicates that
the compressor has an IAMVfwCompressDialogs Interface (see DirectX
documentation). The properties obtained by this interface are stored
in the CompressDialogsProperties member. If false however the
CompressDialogsProperties should be ignored. I have never got a true
value for this parameter (so my implementation may be incorrect).
Consequently no support for using information obtained by this
interface is currently supported.

CompressDialogsProperties cdp - This object has two members which
indicate whether certain dialog boxes exist (this is a throw back
from the old vfw - video for windows implementation). If the values
are true it means the specified dialog box ("About" or "Configure")
exists.


Once you have a filled in CompressorProperties object you can display
the results using the DisplayCompressorProperties() function, but
only if the project is a console application. If not, you are of
course free to implement your own method of displaying the
information.


Once a compressor has been decided you can set it (and its
properties) using the CompressorPropertiesToSet object "compressProp"
in the VideoProperties object passed into the CreaterFilterGraph()
function.

The CompressorPropertiesToSet object has the following members:

char* Name - The Friendly Name of the compressor that you want to
compress the video eg. "Microsoft Video 1". Note that you won't be
able to view the video you create, unless the computer you view it on
has the corresponding decompressor. The Name should point to a char
array that contains the null terminator. The allocation and
destruction of this array is the responsibility of the user.

bool bSet_Quality - This member like the other three bools is
initialized by the constructor to be false. If you wish to set the
Quality the compressor should compress to, set this value to true
and fill in the corresponding Quality member. The CreateFilterGraph()
function will query the compressor for its properties and if it finds
that the compressor does not support changing the quality it will
simply ignore this request. If the member is set to false the
compressor will just use its default value.

double Quality - Can be any value between 0 and 1 (most compressors
only require 2 decimal places of accuracy).

The other members are implemented in a similar way to
bool bSet_Quality and double Quality, but I really don't understand
how to use them correctly so I don't mess around with them,
and let the compressor use its default values. Feel free to try to
set different values but be warned that they may not have been
implemented correctly.



Using The Compression Properties Dialog Box
===========================================

In order to use the dialog you must have the template inserted into
your application's resource script. For the library to know the
values assigned in "resource.h" to the various controls, you must
fill in a ResourceValues structure (either manually or using its
Set() function) and then call the SetResourceValues() function. This
function only needs to be called once after Create() is called. If
the Resource Values are not set the Dialog Box will not be created
properly or at all. If Destroy() is called the VideoCapture object
will lose its knowledge of the ResourceValues, and they will need to
be set again.

The ResourceValue object has the following members:

int m_IDD_COMPRESS_DIALOG - Set it to the ID of the Dialog resource.
int m_IDC_COMBO - Set it to the ID of the drop down ComboBox control.
int m_IDC_CONFIGURE - Set it to the ID of the "Configure" button.
int m_IDC_ABOUT - Set it to the ID of the "About" button.
int m_IDOK - Set it to the ID of the "OK" button.
int m_IDC_SCROLLBAR - Set it to the ID of the horizontal ScrollBar.
int m_IDC_QUALITY_TEXT - Set it to the ID of the "Quality" text.
int m_IDC_VALUE - Set it to the ID of the "100%" text.

After doing the above you can call DisplayCompressorDialog() but you
will soon discover that only the option of choosing "(Uncompressed)"
is available (which is not recommended due to large file sizes). To
remedy this you must call InitArray() which finds and stores all the
possible compressors on your system. You can update the list by
calling InitArray() again but usually there is no need. If you wish
to free the memory that InitArray() allocates call the function
CleanupArray() although there is usually no need as calling Destroy()
or the destructor of the VideoCapture object will take care of this
for you. Another function you may have noticed is the
ReleaseArrayGraph() this is called to ensure that resources are freed
so that they can be used in capturing the video. There is no reason
why you would ever want to call this function (except of course if
you are me, and want to call it for bug catching purposes).

Once InitArray() has been called, a call to DisplayCompressorDialog()
will contain a list of compressors. The first parameter of
DisplayCompressorDialog() is a pointer to the HWND of the parent
window (typecast to void*), this parameter can be NULL to indicate
that it has no parent. The second parameter is a pointer to a
VideoProperties object. The only values that need to be set for the
functions purposes are the width, height, format, and bCreateBuffer
members, the rest will be ignored. It will use these values to see
if the compressor can connect to a source filter that exhibits these
values, if it can't it will refuse to let you select the compressor
under the given configuration. If the compressor has a Configure
dialog the "Configure" button will be enabled and clicking it will
cause the dialog to be displayed. If the compressor doesn't connect
try changing its configuration via the "Configure" button. The
properties are also needed to sort out a bug with the Configure
dialog. If the compressor is not connected to a source it may not
reflect the changes you save through the Configure dialog, I'm pretty
sure it does remember, but if you press the "Configure" button again
it sometimes wipes over your choices and displays its default values.
To remedy this it is highly recommended that you always set resonable
values (as close as possible to what you will actually pass to 
CreateFilterGraphManager() ). You can pass in NULL for the second
parameter to DisplayCompressorDialog(), in which case it will allow
you to choose any compressor without checking whether they connect,
and may exhibit the bug previously described, so it is not
recommended.

Lastly the user should be aware that the functions...

InitArray()
CleanupArray()
ReleaseArrayGraph()
DisplayCompressorDialog()

...cannot be called between Init() and Cleanup() calls. They also
can only be called between calls to Create() and Destroy(). So if
Init() is called you must call Cleanup() before trying to call the
above functions. 



Miscellaneous Information
=========================

The files were made using:
	VC++ 6.0
	DirectX 9.0b (Summer Update)
The debug library strmbasd.lib was used. It was compiled from the
BASECLASSES folder in the DirectX SDK. I am unsure whether this
library will still work when using newer editions of DirectX.

This version was completed on the 15th of September 2005
by Rahil Baber.